Skip to content

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Dec 4, 2025

User description

Benchmark PR discourse#36210

Type: Clean (correct implementation)

Original PR Title: FEATURE: Automatically add 'Add Translation' post menu when content localization enabled
Original PR Description: Many users have been tripping over not seeing this post menu item, so we'll add it automatically.

Meta: https://meta.discourse.org/t/automatically-add-the-add-translation-post-menu-button-when-content-localization-is-enabled/389557
Original PR URL: discourse#36210


PR Type

Enhancement


Description

  • Automatically add 'addTranslation' button to post menu when content localization is enabled

  • Insert button after 'edit' button or at start if edit doesn't exist

  • Apply changes to both post_menu and post_menu_hidden_items settings

  • Update system tests to use new post action menu navigation pattern


Diagram Walkthrough

flowchart LR
  A["content_localization_enabled = true"] -->|triggers| B["Setting change handler"]
  B -->|processes| C["post_menu setting"]
  B -->|processes| D["post_menu_hidden_items setting"]
  C -->|inserts after edit| E["addTranslation button added"]
  D -->|inserts after edit| F["addTranslation button added"]
Loading

File Walkthrough

Relevant files
Enhancement
014-track-setting-changes.rb
Auto-add translation button to post menus                               

config/initializers/014-track-setting-changes.rb

  • Added logic to automatically insert 'addTranslation' button when
    content_localization_enabled is set to true
  • Processes both post_menu and post_menu_hidden_items settings
  • Inserts button after 'edit' button if present, otherwise at position 0
  • Skips insertion if 'addTranslation' already exists in the menu
+12/-0   
Tests
content_localization_setting_spec.rb
Add comprehensive tests for localization setting changes 

spec/initializers/content_localization_setting_spec.rb

  • New test file with 8 comprehensive test cases
  • Tests insertion of 'addTranslation' after 'edit' button in post_menu
  • Tests insertion at start when 'edit' button doesn't exist
  • Tests that duplicate 'addTranslation' buttons are not added
  • Tests that setting is not modified when content localization is
    disabled
  • Mirrors tests for both post_menu and post_menu_hidden_items settings
+81/-0   
post_translation_spec.rb
Refactor tests to use post action menu helpers                     

spec/system/post_translation_spec.rb

  • Updated test setup to set post_menu_hidden_items before enabling
    content localization
  • Replaced direct DOM selector calls with helper methods
    click_post_action_button
  • Changed from using .post-action-menu-edit-translations-trigger to
    calling :show_more then :add_translation actions
  • Updated 12+ test cases to use new navigation pattern for accessing
    translation features
  • Fixes test to use markdown_post.post_number instead of hardcoded post
    number in one case
+30/-14 

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logging: The automatic mutation of settings post_menu and post_menu_hidden_items when
content_localization_enabled becomes true is not accompanied by any audit/event logging to
record who triggered the change and what was changed.

Referred Code
if name == :content_localization_enabled && new_value == true
  %i[post_menu post_menu_hidden_items].each do |setting_name|
    current_items = SiteSetting.get(setting_name).split("|")
    if current_items.exclude?("addTranslation")
      edit_index = current_items.index("edit")
      insert_position = edit_index ? edit_index + 1 : 0
      current_items.insert(insert_position, "addTranslation")
      SiteSetting.set(setting_name, current_items.join("|"))
    end
  end
end

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Edge cases unhandled: The code assumes SiteSetting.get(setting_name) returns a non-nil string and splits on
"|" without guarding against nil/blank or malformed values, and updates settings
without handling potential failures.

Referred Code
current_items = SiteSetting.get(setting_name).split("|")
if current_items.exclude?("addTranslation")
  edit_index = current_items.index("edit")
  insert_position = edit_index ? edit_index + 1 : 0
  current_items.insert(insert_position, "addTranslation")
  SiteSetting.set(setting_name, current_items.join("|"))
end

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Avoid modifying settings as a side-effect

Instead of modifying the post_menu settings as a side-effect when
content_localization_enabled is toggled, the 'addTranslation' button should be
conditionally rendered in the UI. This avoids unexpected changes to stored
configurations and handles cases where the feature is disabled.

Examples:

config/initializers/014-track-setting-changes.rb [91-101]
  if name == :content_localization_enabled && new_value == true
    %i[post_menu post_menu_hidden_items].each do |setting_name|
      current_items = SiteSetting.get(setting_name).split("|")
      if current_items.exclude?("addTranslation")
        edit_index = current_items.index("edit")
        insert_position = edit_index ? edit_index + 1 : 0
        current_items.insert(insert_position, "addTranslation")
        SiteSetting.set(setting_name, current_items.join("|"))
      end
    end

 ... (clipped 1 lines)

Solution Walkthrough:

Before:

# config/initializers/014-track-setting-changes.rb

DiscourseEvent.on(:site_setting_changed) do |name, old_value, new_value|
  if name == :content_localization_enabled && new_value == true
    %i[post_menu post_menu_hidden_items].each do |setting_name|
      current_items = SiteSetting.get(setting_name).split("|")
      if current_items.exclude?("addTranslation")
        # ... logic to find insert position
        current_items.insert(insert_position, "addTranslation")
        SiteSetting.set(setting_name, current_items.join("|"))
      end
    end
  end
end

After:

# config/initializers/014-track-setting-changes.rb
# The entire block for handling :content_localization_enabled would be removed.

# In the relevant frontend component (conceptual):
function getPostMenuItems() {
  let menuItems = SiteSettings.post_menu.split("|");
  if (SiteSettings.content_localization_enabled) {
    if (!menuItems.includes("addTranslation")) {
      // ... logic to find insert position
      menuItems.insert(insertPosition, "addTranslation");
    }
  } else {
    // This part is missing in the current PR
    menuItems = menuItems.filter(item => item !== "addTranslation");
  }
  return menuItems;
}
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a significant design flaw: the PR modifies a site setting as a side-effect but fails to revert the change when the feature is disabled, leading to an inconsistent configuration state.

Medium
Possible issue
Prevent potential crash from nil

Add .to_s before calling .split("|") on the result of
SiteSetting.get(setting_name) to prevent a potential crash if the setting value
is nil.

config/initializers/014-track-setting-changes.rb [93]

-current_items = SiteSetting.get(setting_name).split("|")
+current_items = SiteSetting.get(setting_name).to_s.split("|")
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential NoMethodError if SiteSetting.get returns nil, and the proposed fix using .to_s is a robust way to prevent a crash.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants